package com.feiyuan.book.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.feiyuan.book.entity.BookChapterEntity;
import com.feiyuan.book.entity.BookClassifyEntity;
import com.feiyuan.book.entity.BookUserShelfEntity;
import com.feiyuan.book.service.BookChapterService;
import com.feiyuan.book.service.BookClassifyService;
import com.feiyuan.book.service.BookUserShelfService;
import com.feiyuan.book.vo.BookChapterVO;
import com.feiyuan.book.vo.BookInfoVO;
import com.feiyuan.book.vo.SearchBookVO;
import com.feiyuan.book.webmagic.bqg.processor.BookInfoProcessor;
import com.feiyuan.common.entity.UserEntity;
import com.feiyuan.common.exception.RRException;
import com.feiyuan.common.utils.CommonUtils;
import com.feiyuan.common.utils.Constant;
import org.htmlunit.WebClient;
import org.htmlunit.html.DomAttr;
import org.htmlunit.html.DomText;
import org.htmlunit.html.HtmlPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feiyuan.common.utils.PageUtils;
import com.feiyuan.common.utils.Query;

import com.feiyuan.book.dao.BookListDao;
import com.feiyuan.book.entity.BookListEntity;
import com.feiyuan.book.service.BookListService;
import org.springframework.transaction.annotation.Transactional;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Spider;

import javax.servlet.http.HttpServletRequest;

/**
 * 书籍列表服务
 */
@Service("bookListService")
public class BookListServiceImpl extends ServiceImpl<BookListDao, BookListEntity> implements BookListService {

    @Autowired
    private BookClassifyService bookClassifyService;
    @Autowired
    private BookChapterService bookChapterService;
    @Autowired
    private BookUserShelfService bookUserShelfService;
    @Autowired
    private RedisTemplate redisTemplate;

    private final Logger logger = LoggerFactory.getLogger(BookListServiceImpl.class);

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<BookListEntity> page = this.page(
                new Query<BookListEntity>().getPage(params),
                new QueryWrapper<BookListEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<SearchBookVO> searchBQGBook(String bookNameOrAuthor) {
        try (WebClient webClient = new WebClient()) {
            webClient.getOptions().setThrowExceptionOnScriptError(false);
            // 启用 JavaScript 执行
            webClient.getOptions().setJavaScriptEnabled(true);

            String str = CommonUtils.getUtf8(bookNameOrAuthor);
            String url = Constant.BQG_BASE_URL +  "/s?q=" + str;
            // 获取页面
            HtmlPage page = webClient.getPage(url);

            // 等待 JavaScript 执行完成
            webClient.waitForBackgroundJavaScript(10000);

            // 获取页面源码
//            String pageSource = page.asXml();
//            System.out.println(pageSource);

            // 小说详细地址
            List<DomAttr> bookDetailUrl = page.getByXPath("//div[@class='so_list bookcase']//div[@class='type_show']//div[@class='bookimg']//a/@href");
            // 小说封面
            List<DomAttr> bookImgUrl = page.getByXPath("//div[@class='so_list bookcase']//div[@class='type_show']//div[@class='bookimg']//img/@src");
            // 小说名称
            List<DomText> bookNames = page.getByXPath("//div[@class='so_list bookcase']//div[@class='type_show']//div[@class='bookinfo']//h4[@class='bookname']//a/text()");
            // 小说作者
            List<DomText> bookAuthors = page.getByXPath("//div[@class='so_list bookcase']//div[@class='type_show']//div[@class='bookinfo']//div[@class='author']/text()");
            // 小说简介
            List<DomText> bookProfiles = page.getByXPath("//div[@class='so_list bookcase']//div[@class='type_show']//div[@class='bookinfo']//div[@class='uptime']/text()");

            // 重新组装，生成新的结果
            List<SearchBookVO> bookVOS = new ArrayList<>();
            for(int i=0;i<bookDetailUrl.size();i++) {
                SearchBookVO book = new SearchBookVO();
                book.setBookWebUrl(bookDetailUrl.get(i).getValue());
                book.setBookName(bookNames.get(i).getTextContent());
                book.setBookImgUrl(bookImgUrl.get(i).getValue());
                book.setBookAuthor(bookAuthors.get(i).getTextContent());
                book.setBookProfile(bookProfiles.get(i).getTextContent());
                bookVOS.add(book);
            }
            logger.info("搜索书籍或者作者【{}】后最后的结果为:{}", bookNameOrAuthor, bookVOS);

            return bookVOS;
        } catch (Exception e) {
            logger.error("搜索笔趣阁书籍【{}】时出错了，出错原因为：{}", bookNameOrAuthor, e.getMessage());
            return null;
        }
    }

    @Override
    public BookInfoVO bqgBookInfo(String bookUrl, Boolean isLogin, HttpServletRequest request) {
        // 通过书籍网络ID查询此书籍是否在数据库中
        BookListEntity bookList = this.baseMapper.selectOne(new QueryWrapper<BookListEntity>().eq("book_web_id", this.getBqgBookWebId(bookUrl)));
        if (bookList == null) {
            String bookWebId = this.getBqgBookWebId(bookUrl);
            // 重新组装书籍地址
            bookUrl = Constant.BQG_BASE_URL + bookUrl;

            // 同步查询
            Spider spider = Spider.create(new BookInfoProcessor());
            ResultItems result = spider.get(bookUrl);
            if (result == null) {
                throw new RRException("网络出错，请重试！", 500);
            }
            BookInfoVO bookInfoVO = result.get("bookInfo");
            bookInfoVO.setBookWebId(bookWebId);
            return bookInfoVO;
        } else {
            BookInfoVO bookInfo = new BookInfoVO();
            bookInfo.setImgUrl(bookList.getBookWebImg());
            bookInfo.setBookName(bookList.getBookName());
            bookInfo.setAuthor(bookList.getAuthor());
            bookInfo.setBookUpdateTime(bookList.getLastUpdateTime());
            bookInfo.setBookStatus(this.getBookStatusText(bookList.getStatus()));
            bookInfo.setBookLastChapter(bookList.getLastUpdateChapterName());
            bookInfo.setBookProfile(bookList.getBookProfile());
            bookInfo.setBookWebId(bookList.getBookWebId());
            List<BookChapterEntity> bookChapters = bookChapterService.list(new QueryWrapper<BookChapterEntity>().eq("book_id", bookList.getId()));
            List<BookChapterVO> bookChapterVOS = new ArrayList<>();
            for (BookChapterEntity bookChapter : bookChapters) {
                BookChapterVO bookChapterVO = new BookChapterVO();
                bookChapterVO.setChapterName(bookChapter.getChapterName());
                String chapterUrl = "";
                if (bookChapter.getChapterWebHref().contains(Constant.BQG_BASE_URL)) {
                    chapterUrl = bookChapter.getChapterWebHref().replace(Constant.BQG_BASE_URL, "");
                } else {
                    chapterUrl = bookChapter.getChapterWebHref();
                }
                bookChapterVO.setChapterUrl(chapterUrl);
                bookChapterVOS.add(bookChapterVO);
            }
            bookInfo.setBookChapterList(bookChapterVOS);
            if (isLogin) {
                String token = request.getHeader("token");
                String user = (String) redisTemplate.opsForValue().get(Constant.APP_USER_KEY + token);
                UserEntity userEntity = JSONObject.parseObject(user, UserEntity.class);
                BookUserShelfEntity bookUserShelf = bookUserShelfService.getOne(new QueryWrapper<BookUserShelfEntity>().eq("user_id", userEntity.getUserId()).eq("book_id", bookList.getId()));
                if (bookUserShelf != null) {
                    bookInfo.setIsShelf(true);
                } else {
                    bookInfo.setIsShelf(false);
                }
            } else {
                bookInfo.setIsShelf(false);
            }
            return bookInfo;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object bqgJoinShelf(BookInfoVO bookInfo, UserEntity user) {
        this.bqgSaveBook(bookInfo, user);
        return "OK";
    }

    /**
     * 获取分类ID
     * @param bookType 书籍分类
     * @return Long
     */
    private Long getClassifyId(String bookType) {
        Long classifyId = 0l;
        // 1.查询所有的分类
        List<BookClassifyEntity> classifyList = bookClassifyService.list();
        for (BookClassifyEntity bookClassifyEntity : classifyList) {
            if (bookType.contains(bookClassifyEntity.getClassifyName())) {
                classifyId = bookClassifyEntity.getId();
                break;
            }
        }
        return classifyId;
    }

    /**
     * 获取笔趣阁书籍状态码
     */
    private Integer getBookStatus(String bookStatus) {
        if(bookStatus.contains("连载")) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * 获取笔趣阁书籍状态文字
     */
    private String getBookStatusText(Integer bookStatus) {
        if (bookStatus == 0) {
            return "状态：连载";
        } else {
            return "状态：已完结";
        }
    }

    /**
     * 保存笔趣阁书籍信息
     * @param bookInfo 书籍信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void bqgSaveBook(BookInfoVO bookInfo, UserEntity user) {
        // 1.查询数据库中是否存在次书籍
        BookListEntity bookList = this.baseMapper.selectOne(new QueryWrapper<BookListEntity>().eq("book_web_href", Constant.BQG_BASE_URL + bookInfo.getBookWebUrl()));
        if (bookList == null) {
            BookListEntity book = new BookListEntity();
            book.setClassifyId(this.getClassifyId(bookInfo.getBookType()));
            book.setBookName(bookInfo.getBookName());
            book.setAuthor(bookInfo.getAuthor());
            book.setBookProfile(bookInfo.getBookProfile());
            book.setLastUpdateTime(bookInfo.getBookUpdateTime());
            book.setLastUpdateChapterName(bookInfo.getBookLastChapter());
            book.setBookWebId(this.getBqgBookWebId(bookInfo.getBookWebUrl()));
            book.setBookWebHref(Constant.BQG_BASE_URL + bookInfo.getBookWebUrl());
            book.setLastUpdateChapterWebId(this.getChapterWebId(bookInfo.getBookLastChapterUrl()));
            book.setCreateTime(new Date());
            book.setUpdateTime(new Date());
            book.setStatus(this.getBookStatus(bookInfo.getBookStatus()));
            book.setBookWebImg(bookInfo.getImgUrl());
            this.baseMapper.insert(book);

            // 2.保存章节信息
            List<BookChapterEntity> chapterList = new ArrayList<>();
            for(BookChapterVO chapterVO: bookInfo.getBookChapterList()) {
                BookChapterEntity chapter = new BookChapterEntity();
                chapter.setBookId(book.getId());
                chapter.setChapterName(chapterVO.getChapterName());
                chapter.setChapterWebHref(Constant.BQG_BASE_URL + chapterVO.getChapterUrl());
                chapter.setChapterWebId(this.getChapterWebId(chapterVO.getChapterUrl()));
                Date date = new Date();
                chapter.setCreateTime(date);
                chapter.setUpdateTime(date);
                chapterList.add(chapter);
            }
            bookChapterService.saveBatch(chapterList);

            // 3.加入用户书架
            BookUserShelfEntity bookUserShelf = new BookUserShelfEntity();
            bookUserShelf.setBookId(book.getId());
            bookUserShelf.setUserId(user.getUserId());
            Date date = new Date();
            bookUserShelf.setCreateTime(date);
            bookUserShelf.setUpdateTime(date);
            bookUserShelfService.save(bookUserShelf);
        } else {
            // 3.加入用户书架
            BookUserShelfEntity bookUserShelf = new BookUserShelfEntity();
            bookUserShelf.setBookId(bookList.getId());
            bookUserShelf.setUserId(user.getUserId());
            Date date = new Date();
            bookUserShelf.setCreateTime(date);
            bookUserShelf.setUpdateTime(date);
            bookUserShelfService.save(bookUserShelf);
        }
    }

    /**
     * 获取笔趣阁书籍在网络上的ID
     * @param bookWebUrl 书籍在网络上的地址
     * @return String
     */
    private String getBqgBookWebId(String bookWebUrl) {
        // String url = "/book/3786/";
        String url = bookWebUrl.replace("/book/", "").replace("/", "");
        return url;
    }

    /**
     * 获取笔趣阁网络上章节的ID
     * @param chapterWebUrl 网络地址
     * @return String
     */
    private String getChapterWebId(String chapterWebUrl) {
        // String url = "/book/3786/1.html";
        String[] urls = chapterWebUrl.split("/");
        String url = urls[urls.length - 1];
        return url.replace(".html", "");
    }

}